﻿//--------------------------------------------------------------
//
//作    者：蒙孝宗
//功能描述：数据库操作辅助类
//创建时间：2012-02-12
//修改记录：2012-02-22 改进事务处理方式
//         2012-04-11 修改读取配置文件的方法
//         2012-04-27 修改 GetProvider 方法,使其支持在同一个线程内可对不同数据库操作
//版    本：V1.3
//
//--------------------------------------------------------------

using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
using System.Xml;
using DbHelper.Driver;
using System.Configuration;

namespace DbHelper.Data
{
    /// <summary>
    /// 创建获取数据对象的实例
    /// </summary>
    public class MDbService
    {
        /// <summary>
        /// 缓存数据库驱动
        /// </summary>
        private static Dictionary<string, IDriver> dictDriver = null;

        /// <summary>
        /// 缓存数据库相关信息
        /// </summary>
        private static Dictionary<int, KeyValuePair<string, string>> dictConnString = new Dictionary<int, KeyValuePair<string, string>>();

        [ThreadStatic]
        private static Dictionary<int, IProvider> dictProvider = null;
        [ThreadStatic]
        private static IProvider curProvider = null;
        [ThreadStatic]
        private static int curid = int.MinValue;

        //记录注册的第一个ID
        private static bool isSeted = false;
        private static int firstid = 0;


        /// <summary>
        /// 注册数据库驱动
        /// </summary>
        private static void RegisterDriver()
        {
            string cfgPath = System.IO.Path.Combine(
                System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase),
                "DbHelper.dll.config");

            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(cfgPath);
            XmlNodeList nodes = xmlDoc.SelectNodes("/Driver/Items/add");

            dictDriver = new Dictionary<string, IDriver>(4);

            foreach (XmlNode node in nodes)
            {
                Assembly asm = Assembly.Load(node.Attributes["assembly"].Value);
                dictDriver[node.Attributes["name"].Value] = (IDriver)asm.CreateInstance(node.Attributes["type"].Value);
            }
        }

        /// <summary>
        /// 注册数据库
        /// </summary>        
        /// <param name="id"></param>
        /// <param name="driverName">驱动器名称</param>
        /// <param name="connString">数据库连接字符串</param>
        public static void RegisterProvider(int id, string driverName, string connString)
        {
            lock (typeof(MDbService))
            {
                if (dictDriver == null) RegisterDriver();
                if (isSeted == false) { firstid = id; isSeted = true; }
                dictConnString[id] = new KeyValuePair<string, string>(driverName, connString);
            }
        }

        /// <summary>
        /// 获取数据库服务实例
        /// <para>注意：不应该缓存，应该每次都读取。原因是不同的线程会得到不同的对象，在同一个线程内只会返回同一个对象</para>
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public static IProvider GetProvider(int id)
        {
            if (curid != id)
            {
                curid = id;

                if (dictProvider == null) dictProvider = new Dictionary<int, IProvider>();

                if (!dictProvider.TryGetValue(id, out curProvider))
                {
                    curProvider = CreateProvider(dictDriver[dictConnString[id].Key], dictConnString[id].Value);
                    dictProvider.Add(id, curProvider);
                }
            }

            return curProvider;
        }

        /// <summary>
        /// 获取注册的第一个数据库服务实例
        /// <para>注意：不应该缓存，应该每次都读取。原因是不同的线程会得到不同的对象，在同一个线程内只会返回同一个对象</para>
        /// </summary>
        /// <returns></returns>
        public static IProvider GetProvider()
        {
            return GetProvider(firstid);
        }

        /// <summary>
        /// 创建数据库服务实例
        /// </summary>
        /// <param name="dbDriver"></param>
        /// <param name="connString"></param>
        /// <returns></returns>
        private static IProvider CreateProvider(IDriver dbDriver, string connString)
        {
            return new DbProvider(dbDriver, connString);
        }
    }
}
